package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyTest {
    public static void main(String[] args) throws ReflectiveOperationException {
        var elements = new Object[1000];

        for (int i = 0; i < elements.length; i++) {
            Integer value = i + 1;
            elements[i] = Proxy.newProxyInstance(
                    Integer.class.getClassLoader(),
                    new Class[]{Comparable.class},  // 接口数组，代理会实现数组里面的各个接口
                    new TraceHandler(value)
            );
        }

        // 最终elements[0] 会是类似下面这个类的一个实例
        // 5个实现方法分别调用InvocationHandler的invoke方法，并传递反射得到的原始方法作为参数
        // public final class jdk.proxy1.$Proxy0 extends java.lang.reflect.Proxy implements java.lang.Comparable {
        //     private static final java.lang.reflect.Method m0;
        //     private static final java.lang.reflect.Method m1;
        //     private static final java.lang.reflect.Method m2;
        //     private static final java.lang.reflect.Method m3;

        //     public jdk.proxy1.$Proxy0(java.lang.reflect.InvocationHandler);

        //     public final boolean equals(java.lang.Object);
        //     public final java.lang.String toString();
        //     public final int hashCode();
        //     public final int compareTo(java.lang.Object);
        //     private static java.lang.invoke.MethodHandles$Lookup proxyClassLookup(java.lang.invoke.MethodHandles$Lookup);
        // }

        Integer key = (int)(Math.random() * elements.length) + 1;
        int result = Arrays.binarySearch(elements, key);

        if (result >= 0) {
            System.out.println(elements[result]);
        } else {
            System.out.println("Can't find " + key);
        }
    }
}

class TraceHandler implements InvocationHandler {
    private Object target;

    public TraceHandler(Object t) {
        target = t;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        // 打印目标
        System.out.print(target);

        // 打印方法名
        System.out.print("." + m.getName() + "(");

        // 打印参数
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                System.out.print(args[i]);
                if (i < args.length - 1) {
                    System.out.print(", ");
                }
            }
        }

        System.out.println(")");

        // 调用目标方法
        return m.invoke(target, args);
    }
}


